﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;

namespace ApiBetaSeries.Version
{
    public static class APIVersion
    {
        /// <summary>
        /// Last update of this lib
        /// </summary>
        static public DateTime LastUpdate
        {
            get { return new DateTime(2010, 12, 22); }
        }
        static private List<MethodVersion> m_apiMethodVersion;

        /// <summary>
        /// Get all the method out of date
        /// </summary>
        /// <returns>list of the name of the method out of date</returns>
        static public List<string> MethodOutOfDate()
        {
            List<string> list = new List<string>();
            Dictionary<MethodInfo, ApiMethod> listMethods = LoadMethod();
            GetMethodVersion();

            foreach (MethodInfo method in listMethods.Keys)
            {
                foreach (string url in listMethods[method].Url)
                {
                    MethodVersion version = SearchMethodVersion(url);
                    if (version == null)
                    {
                        throw new Exception("La méthode " + method + " utilise l'url " + url + " qui n'existe pas.");
                    }
                    if (version.Updated > LastUpdate)
                    {
                       

                        list.Add(method.ToGoodString());
                        // On sort de la boucle de la list des url
                        break;
                    }
                }
            }
            return list;
        }

        /// <summary>
        /// Get all the method out of date with call to the API (not just bridge)
        /// </summary>
        /// <returns>list of the name of the method out of date</returns>
        static public List<string> MethodOutOfDateWithCode()
        {
            List<string> list = new List<string>();
            Dictionary<MethodInfo, ApiMethod> listMethods = LoadMethod();
            GetMethodVersion();

            foreach (MethodInfo method in listMethods.Keys)
            {
                if (listMethods[method].Code)
                {
                    foreach (string url in listMethods[method].Url)
                    {
                        MethodVersion version = SearchMethodVersion(url);
                        if (version == null)
                        {
                            throw new Exception("La méthode " + method + " utilise l'url " + url + " qui n'existe pas.");
                        }
                        if (version.Updated > LastUpdate)
                        {


                            list.Add(method.ToGoodString());
                            // On sort de la boucle de la list des url
                            break;
                        }
                    }
                }
            }
            return list;
        }

        /// <summary>
        /// Return if this lib is up to date
        /// </summary>
        /// <returns></returns>
        static public bool IsUpToDate()
        {
            return MethodOutOfDate().Count == 0;
        }
        

        #region Internal methods

        static internal MethodVersion SearchMethodVersion(string name)
        {
            foreach (MethodVersion v in m_apiMethodVersion)
            {
                if (string.Equals(v.Name, name, StringComparison.InvariantCultureIgnoreCase))
                    return v;
            }

            return null;
        }

        static internal void GetMethodVersion()
        {
            m_apiMethodVersion = new List<MethodVersion>();
            XmlDocument xdoc = Utils.UtilsXML.GetUrl("/status.xml");
            foreach (XmlElement method in xdoc.GetElementsByTagName("method"))
            {
                MethodVersion m = new MethodVersion();
                m.Name = Utils.UtilsXML.GetStringValue(method, "name");
                try
                {
                    string format = Utils.UtilsXML.GetStringValue(method, "created");
                    format = format.Insert(6,"/");
                    format = format.Insert(4,"/");
                    m.Created = DateTime.Parse(format);
                }
                catch (Exception)
                {
                    m.Created = DateTime.MinValue;
                }
                try
                {
                    string format = Utils.UtilsXML.GetStringValue(method, "updated");
                    format = format.Insert(6, "/");
                    format = format.Insert(4, "/");
                    m.Updated = DateTime.Parse(format);
                }
                catch (Exception)
                {
                    m.Created = DateTime.MinValue;
                }
                m_apiMethodVersion.Add(m);
            }
        }



        internal static Dictionary<MethodInfo, ApiMethod> LoadMethod()
        {
            Assembly ass = Assembly.GetExecutingAssembly();
            Dictionary<MethodInfo, ApiMethod> list = new Dictionary<MethodInfo, ApiMethod>();

            foreach (Type type in ass.GetTypes())
            {
                foreach (MethodInfo member in type.GetMethods())
                {
                    ApiMethod[] method =  (ApiMethod[]) member.GetCustomAttributes(typeof(ApiMethod), true);
                    if (method.Length > 0)
                    {
                        list.Add(member, method[0]);
                    }
                }
            }
            return list;
        }
        /// <summary>
        ///  Version of a method on the API Betaseries
        /// </summary>
        internal class MethodVersion
        {
            public string Name { get; set; }
            public DateTime Created { get; set; }
            public DateTime Updated { get; set; }
        }

        #endregion Internal methods
    }
}
